/*
    Author: Christopher Diggins
    License: MIT Licence 1.0
    Website: http://www.cdiggins.com
*/

#ifndef CVML_OPCODES_HPP
#define CVML_OPCODES_HPP

const int MAX_SUB_OPCODES = 16;

enum OpCodeEnum
{
    op_noop, // do nothing 

    // literals
	op_int_8,	// N=1 bytes	
    op_int_16,	// N=2 bytes	
	op_push_short = op_int_16,
    op_int_32,	// N=4 bytes
	op_push_int = op_int_32,
    op_int_64,  // N=8 bytes
    op_int_128, // N=16 bytes

	op_uint_8,	// N=1 bytes
	op_push_byte = op_uint_8,
    op_uint_16,	// N=2 bytes	
    op_uint_32,	// N=4 bytes	
    op_uint_64, // N=8 bytes
    op_uint_128,// N=16 bytes

	// IEEE 754-2008, binary floating point
	op_bin_16,	// N=2 bytes
	op_bin_32,	// N=4 bytes
	op_push_flt = op_bin_32,
	op_bin_64,	// N=8 bytes
	op_push_dbl = op_bin_64,
	op_bin_128,	// N=16 bytes

	// IEEE 754-2008, decimal floating point
	op_dec_16,	// N=2 bytes
	op_dec_32,	// N=4 bytes
	op_dec_64,	// N=8 bytes
	op_dec_128, // N=16 bytes

	op_push_char,
	op_push_wchar,	

	op_type_of,		// Gets a value's type
	op_prim_type,	// N=1 bytes, pushes a value representing one of the primitive types
	op_cast_to,		// Casts from one type to another.
	op_cast_prim,	// N=1 bytes, Casts to a primitive type

    op_push_string,		// string of 8-bit chars
    op_push_wstring,	// string of 16-bit chars
    
	op_push_sub,	// N=4 bytes

	// constants
    op_push_true,	// push a boolean true value
    op_push_false,	// push a boolean false value

	// stack shuffling 
	op_pop,		// remove top of the stack
	op_popN,	// N=1 byte, remove top N values from the stack
	op_zapN,	// N=1 byte, remove the Nth value (zapN(0) == pop)
    op_dup,		// duplicate the top value on the stack
	op_dupN,	// N=1 byte, duplicates the n top values.
    op_swap,	// swap the top two values on the stack 
    op_swapN,	// N=1 byte, swap the top values on the stack, with the nth value, swapN(0) == noop, swapN(1) == swap 
    op_getN,	// N=1 byte, gets a copy of the Nth value and places it on top, getN(0) == dup
    op_setN,	// N=1 byte, moves the top value over the nth value below it, setN(0) == zapN(1)
	op_digN,	// N=1 byte, move the nth value to the top of the stack, digN(0) == noop, digN(1) == swap
	op_buryN,	// N=1 byte, move the top value underneath the nth item, buryN(0) == swap
    
    // polymorphic comparison operators
    op_lt, 
    op_gt, 
    op_lteq, 
    op_gteq, 
    op_eq, 
    op_neq,

    // polymorphic arithmetic 
    op_add, 
    op_sub, 
    op_div, 
    op_mul,
    op_mod,
    op_neg,
    
    // integer comparison operators
    op_lt_int, 
    op_gt_int, 
    op_lteq_int, 
    op_gteq_int, 
    op_eq_int, 
    op_neq_int,

    // integer arithmetic 
	op_inc,
	op_dec,
    op_add_int, 
    op_sub_int, 
    op_div_int, 
    op_mul_int,
    op_mod_int,
    op_neg_int,
    
    // floating-point comparison operators
    op_lt_flt, 
    op_gt_flt, 
    op_lteq_flt, 
    op_gteq_flt, 
    op_eq_flt, 
    op_neq_flt,

    // floating point arithmetic 
    op_add_flt, 
    op_sub_flt, 
    op_div_flt, 
    op_mul_flt,
    op_mod_flt,
    op_neg_flt,

	// boolean operations
    op_or,
    op_not,
    op_xor,
    op_and,

    // function calls and control flow
	op_apply,		// call a dynamic function
	op_dip,			// calls a function but temporarily hides the next stack value
	op_sap,			// dip followed by apply
    op_while,		// while not predicate equals true
	op_whilene,		// while not equal to a value
	op_whilenz,		// while not zero on the top of the stack
	op_for, 
    op_foreach,
    op_foreach_index,
    op_forN, 
    op_if_else,				// true [$A] [$B] op_if => $A, false [$A] [$B] op_if => $B
	op_if,
	op_repeat, 
	op_lin_rec,
	op_bin_rec,

	// function terminators 
	op_ret,

	// tail-call 
    op_tail_apply,		
    op_tail_if,		
    op_tail_if_else,
	
	// The following are under consideration
	// tail_dip,
	// tail_sap,

	// dynamic function constructors
	op_quote,	// converts a value into a function: (a -> [a])
	op_papply,	// partial application: (a [b] -> [a b])
	op_papply2,	// partial application: (a b [c] -> [a b c])
	op_papply3, // partial application: (a b c [d] -> [a b c d])
	op_compose, // function composition: ([a] [b] -> [a b])

	// objects
    op_invoke,
	op_get_field, 
    op_set_field, 
    op_get_field_index,
    op_set_field_index,
	op_add_field,
	op_num_fields,
    op_new,
    op_free,
    op_null,

    // arrays, lists, ranges, and generators
    op_new_array,
	op_tuple,
    op_nil,
    op_count, 
    op_get_at,
    op_set_at,
	op_transform_at,
	op_swap_at,
    op_first,
    op_rest,
    op_last,
	op_uncons,
    op_rev,
    op_fold,
	op_reduce,
    op_map,
    op_filter,
    op_filter_map,
    op_range,
    op_empty,
    op_prepend,
    op_append,
	op_slice,
	op_gen,
    op_nats, 

    // used to find a name in the global environment.
    // for example a standard library function 
    op_external, 
	
	//====================================================================
	// These are short-form instructions: 
	// They are subject to change

    op_push_neg1,
    op_push0,
    op_push1,
    op_push2,

    op_dupd, 
    op_dup2,
    op_dup3,

    op_popd,
    op_pop2,
    op_pop3,
    op_pop4,
    op_pop5,
    op_pop6,
    op_pop7,
    op_pop8,

    op_swap1,
    op_swap2,
    op_swap3,
    op_swapd,

    op_get1, 
    op_get2, 
    op_get3, 
    op_get4,
    op_get5, 
    op_get6, 
    op_get7, 
    op_get8,

	op_set1, 
    op_set2, 
    op_set3, 
    op_set4, 
    op_set5, 
    op_set6, 
    op_set7, 
    op_set8, 

	// push functions
	op_push_instr, 
    op_push_sub0,
	op_push_sub1,
	op_push_sub2,
	op_push_sub3,
	op_push_sub4,
	op_push_sub5,
	op_push_sub6,
	op_push_sub7,
	op_push_sub8,
	op_push_sub9,
    op_push_sub10,
	op_push_sub11,
	op_push_sub12,
	op_push_sub13,
	op_push_sub14,
	op_push_sub15,
	op_push_sub_short,

	/*
	// call functions
    op_call_sub0,
	op_call_sub1,
	op_call_sub2,
	op_call_sub3,
	op_call_sub4,
	op_call_sub5,
	op_call_sub6,
	op_call_sub7,
	op_call_sub8,
	op_call_sub9,
    op_call_sub10,
	op_call_sub11,
	op_call_sub12,
	op_call_sub13,
	op_call_sub14,
	op_call_sub15,
	op_call_sub_short,
	*/

	// streams
	op_stdin,
	op_stdout,
	op_stderr,
	op_infile,
	op_outfile,
	op_read,
	op_write,
	op_pipe_to,
	op_pipe_from,

    // parallelization
	op_fork,
    op_make_continuation,
    op_clone_continuation,
    op_run_continuation,

	// signal
	op_wait_on_signal,	// msec -> signal 
	op_send_signal,		// msec -> 

    // exceptions
	op_throw,
	op_try,
	op_catch,
	op_finally,

	// Dynamic code rewriting 
	op_disassemble,
	op_assemble,

	// I am leaving 4 instruction reserved for an implementation to use. 
	op_reserved,
    op_reserved_final = op_reserved + 3
};

#endif


        
